#include<iostream>
#include<cstdlib>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/select.h>
#include<sys/epoll.h>
#include<sys/types.h>
#include<unistd.h>
#include<string.h>
using namespace std;
class ServerTcpIp{
private:
	int sizeAddr;//sizeof(sockaddr_in) connect with addr_in;
	int backwait;//the most waiting clients ;
	int numClient;//how many clients now; 
	int max;//the most clients;
	int fd_count;//sum of clients in fd_set
	int epfd;//file descriptor to ctrl epoll
	char rec[200];//what you receive;
	char sen[200];//what you send;
	char* hostip;//host IP 
	char* hostname;//host name
	int sock;//file descriptor of host;
	int* psockClients;//client[];
	int sockC;//file descriptor to sign every client;
	epoll_event nowEvent;//a temp event to get event
    epoll_event* pevent;//all the event
	sockaddr_in addr;//IPv4 of host;
	sockaddr_in client;//IPv4 of client;
	fd_set  fdClients;//file descriptor
protected:
    int* pfdn;//pointer if file descriptor
    int fdNumNow;//num of fd now
    int fdMax;//fd max num
    bool addFd(int addsoc)
    {
        bool flag=false;
        for(int i=0;i<fdNumNow;i++)
        {
            if(pfdn[i]==0)
            {
                pfdn[i]=addsoc;
                flag=true;
                break;
            }
        }
        if(flag==false)
        {
            if(fdNumNow>=fdMax)
            {
                pfdn=(int*)realloc(pfdn,sizeof(int)*fdMax+32);
                if(pfdn==NULL)
                    exit(0);
                fdMax+=10;
            }
            pfdn[fdNumNow]=addsoc;
            fdNumNow++;
        }
        return true;
    }
    bool deleteFd(int clisoc)
    {
        for(int i=0;i<fdNumNow;i++)
        {
            if(pfdn[i]==clisoc)
            {
                pfdn[i]=0;
                return true;
            }
        }
        return false;
    }
public:
	ServerTcpIp(int epollNum=0,unsigned short port=5200,int wait=5,int maxClient=0)
	{
		sock=socket(AF_INET,SOCK_STREAM,0);//AF=addr family internet
		addr.sin_addr.s_addr=htonl(INADDR_ANY);//inaddr_any
		addr.sin_family=AF_INET;//af_intt IPv4
		addr.sin_port=htons(port);//host to net short
		fd_count=0;// select model
		sizeAddr=sizeof(sockaddr);
		backwait=wait;
		memset(rec,0,20);
		memset(sen,0,20);
		numClient=0;
		hostip=(char*)malloc(sizeof(char)*20);
		memset(hostip,0,sizeof(char)*20);
		hostname=(char*)malloc(sizeof(char)*30);
		memset(hostname,0,sizeof(char)*30);
		FD_ZERO(&fdClients);//clean fdClients;
		epfd=epoll_create(epollNum);
		if((pevent=(epoll_event*)malloc(512*sizeof(epoll_event)))==NULL)
			exit(0);
		memset(pevent,0,sizeof(epoll_event)*512);
		memset(&nowEvent,0,sizeof(epoll_event));
        pfdn=(int*)malloc(sizeof(int)*64);
        if(pfdn==NULL)
            exit(0);
        memset(pfdn,0,sizeof(int)*64);
        fdNumNow=0;
        fdMax=64;
		if(maxClient<=0||maxClient>100)
			psockClients=NULL;
		else 
		{
			psockClients=(int*)malloc(sizeof(int)*maxClient);
			if(psockClients==NULL)
				exit(0);
			max=maxClient;
		}
	}
	~ServerTcpIp()//clean server
	{
		if(psockClients!=NULL)
			free(psockClients);
		close(sock);
		close(sockC);
		close(epfd);
		free(hostip);
		free(hostname);
		free(pevent);
        free(pfdn);
	}
	bool bondhost()//bond myself first
	{
		if(bind(sock,(sockaddr*)&addr,sizeof(addr))==-1)
		{
			//printf("you can not bind\n");
			return false;
		}
		return true;
	}
	bool setlisten()//set listem to accept second
	{
		if(listen(sock,backwait)==-1)
		{
			//printf("listen wrong\n");
			return false;
		}
		FD_SET(sock,&fdClients);
		nowEvent.events=EPOLLIN;
		nowEvent.data.fd=sock;
		epoll_ctl(epfd,EPOLL_CTL_ADD,sock,&nowEvent);
		fd_count++;
		return true;
	}
	bool acceptClient()//wait until success model one
	{
		sockC=accept(sock,(sockaddr*)&client,(socklen_t*)&sizeAddr);
		return true;
	}
	bool acceptClientsModelTwo(int cliNum)//model two
	{
		if(cliNum<max)
		{
			psockClients[cliNum]=accept(sock,(sockaddr*)&client,(socklen_t*)&sizeAddr);
			numClient++;
		}	
		else
		{
			//printf("number has overflow\n");
			return false;
		}
		return true;
	}
	bool receive(char* prec)//model one
	{
		if(recv(sockC,prec,sizeof(rec),0)==-1)
		{
			//printf("%d",GetLastError());
			return false;
		}
		return true;
	}
	bool receiveMystl(void* pget,int len)//model one
	{
		if(recv(sockC,(char*)pget,len,0)==-1)
		{
			//printf("%d",GetLastError());
			return false;
		}
		return true;
	}
	bool receivesModelTwo(char* prec,int cliNum)//model two
	{
		if(recv(psockClients[cliNum],prec,sizeof(rec),0)==-1)
		{
			//printf("%d",GetLastError());
			psockClients[cliNum]=0;
			return false;
		}
		return true;
	}
	bool receiveSMystlModelTwo(void* prec,int cliNum,int len)//model two
	{
		if(recv(psockClients[cliNum],(char*)prec,len,0)==-1)
		{
			//printf("%d",GetLastError());
			psockClients[cliNum]=0;
			return false;
		}
		return true;
	}
	bool sendClient(char* ps)//model one
	{
		if(strlen(ps)>190)
		{
			//printf("send too long\n");
			return false;
		}
		memset(sen,0,200);
		strcpy(sen,ps);
		if(send(sockC,sen,sizeof(sen),0)==-1)
			return false;
		return true;
	}
	bool sendClientMystl(const void* ps,int len)//model one
	{
		if(send(sockC,(char*)ps,len,0)==-1)
			return false;
		return true;
	}
	bool sendClientS(const char* ps,int cliNum)//model two
	{
		if(strlen(ps)>190)
		{
			//printf("send too long\n");
			return false;
		}
		memset(sen,0,200);
		strcpy(sen,ps);
		if(send(psockClients[cliNum],sen,sizeof(sen),0)==-1)
			return false;
		return true;
	}
	bool sendClientSMystlModelTwo(const void* ps,int cliNum,int len)//model two
	{
		if(send(psockClients[cliNum],(char*)ps,len,0)==-1)
			return false;
		return true;
	}
	bool sendClientsEveryoneModelTwo(const char* ps)//model two
	{
		if(strlen(ps)>190)
		{
			//printf("send too long\n");
			return false;
		}
		memset(sen,0,20);
		strcpy(sen,ps);
		for(int i=0;i<numClient;i++)
		{ 
			if(psockClients[i]==0)
				continue;
			send(psockClients[i],sen,sizeof(sen),0);
		}
		return true;
	}
	bool sendClientsEveryoneMystlTwo(const void* ps,int len)//model two
	{
		for(int i=0;i<numClient;i++)
		{ 
			if(psockClients[i]==0)
				continue;
			send(psockClients[i],(char*)ps,len,0);
		}
		return true;
	}
	bool selectModel(int* pthing,int* pnum,char* pget,int (*pfunc)(int i,int num,char* p,ServerTcpIp& it))
	{//0 out,1 in,2 say
		fd_set temp=fdClients;
		memset(rec,0,sizeof(rec));
		int sign=select(0,&temp,NULL,NULL,NULL);
		if(sign>0)
		{
			for(int i=0;i<(int)fdClients.fds_bits[i];i++)
			{
				if(FD_ISSET(fdClients.fds_bits[i],&temp))
				{
					if(fdClients.fds_bits[i]==sock)
					{
						if(fd_count<FD_SETSIZE)
						{
							sockaddr_in newaddr={0};
							int newClient=accept(sock,(sockaddr*)&newaddr,(socklen_t*)&sizeAddr);
                            this->addFd(newClient);
							FD_SET(newClient,&fdClients);
							fd_count++;
							for(int j=0;j<(int)fd_count;j++)
							{
								if(newClient==fdClients.fds_bits[j])
								{
									*pnum=j;
									break;
								}
							}
							*pthing=1;
							strcpy(pget,inet_ntoa(newaddr.sin_addr));
							if(pfunc!=NULL)
							{
								if(pfunc(*pthing,*pnum,pget,*this))
									return false;
							}
						}
						else
							continue;
					}
					else
					{
						int sRec=recv(fdClients.fds_bits[i],rec,sizeof(rec),0);
						*pnum=i;
						if(sRec>0)
						{
							strcpy(pget,rec);
							*pthing=2;
						}
						if(sRec<=0)
						{
							close(fdClients.fds_bits[i]);
							FD_CLR(fdClients.fds_bits[i],&fdClients);
							fd_count--;
                            this->deleteFd(fdClients.fds_bits[i]);
							*(char*)pget=0;
							*pthing=0;
						}
						if(pfunc!=NULL)
						{
							if(pfunc(*pthing,*pnum,pget,*this))
								return false;
						}
					}
				}
			}
		}
		else
		{
			//printf("select wrong\n");
			return false;
		}
		return true;
	}
	bool selectModelMysql(int* pthing,int* pnum,void* pget,int len,void* pneed,int (*pfunc)(int ,int ,void* ,void*,ServerTcpIp& ))
	{//0 out,1 in,2 say
		fd_set temp=fdClients;
		memset(rec,0,sizeof(rec));
		int sign=select(0,&temp,NULL,NULL,NULL);
		if(sign>0)
		{
			for(int i=0;i<(int)fd_count;i++)
			{
				if(FD_ISSET(fdClients.fds_bits[i],&temp))
				{
					if(fdClients.fds_bits[i]==sock)
					{
						if(fd_count<FD_SETSIZE)
						{
							sockaddr_in newaddr={0};
							int newClient=accept(sock,(sockaddr*)&newaddr,(socklen_t*)&sizeAddr);
							FD_SET(newClient,&fdClients);
							this->addFd(newClient);
							fd_count++;
							for(int j=0;j<(int)fd_count;j++)
							{
								if(newClient==fdClients.fds_bits[j])
								{
									*pnum=j;
									break;
								}
							}
							*pthing=1;
							strcpy((char*)pget,inet_ntoa(newaddr.sin_addr));
							if(pfunc!=NULL)
							{
								if(pfunc(*pthing,*pnum,pget,pneed,*this))
									return false;
							}
						}
						else
							continue;
					}
					else
					{
						int sRec=recv(fdClients.fds_bits[i],(char*)pget,len,0);
						*pnum=i;
						if(sRec>0)
						{
							*pthing=2;
						}
						if(sRec<=0)
						{
							close(fdClients.fds_bits[i]);
							this->deleteFd(fdClients.fds_bits[i]);
							FD_CLR(fdClients.fds_bits[i],&fdClients);
							fd_count--;
							*(char*) pget=0;
							*pthing=0;
						}
						if(pfunc!=NULL)
						{
							if(pfunc(*pthing,*pnum,pget,pneed,*this))
								return false;
						}
					}
				}
			}
		}
		else
		{
			//printf("select wrong\n");
			return false;
		}
		return true;
	}
	bool selectSend(const char* ps,int cliNum)
	{
		int clientSent=fdClients.fds_bits[cliNum];
		if(strlen(ps)>190)
			return false;
		memset(sen,0,200);
		strcpy(sen,ps);
		if(send(fdClients.fds_bits[cliNum],sen,sizeof(sen),0)==-1)
			return false;
		return true;
	}
	bool selectSendMystl(const void* ps,int cliNum,int len)
	{
		int clientSent=fdClients.fds_bits[cliNum];
		if(send(fdClients.fds_bits[cliNum],(char*)ps,len,0)==-1)
			return false;
		return true;
	}
	bool selectSendEveryone(char* ps)
	{
		if(strlen(ps)>190) 
		{
			//printf("send too long\n");
			return false;
		}
		memset(sen,0,20);
		strcpy(sen,ps);
		for(int i=0;i<fd_count;i++)
		{ 
			int clientSent=fdClients.fds_bits[i];
			if(clientSent!=0)
				send(fdClients.fds_bits[i],sen,sizeof(sen),0);
		}
		return true;
	}
	bool selectSendEveryoneMystl(void* ps,int len)
	{
		for(int i=0;i<fd_count;i++)
		{ 
			int clientSent=fdClients.fds_bits[i];
			if(clientSent!=0)
				send(fdClients.fds_bits[i],(char*)ps,len,0);
		}
		return true;
	}
	bool updateSocketSelect(int* p,int* pcount)
	{
		if(fd_count!=0)
			*pcount=fd_count;
		else
			return false;
		for(int i=0;i<fd_count;i++)
			p[i]=fdClients.fds_bits[i];
		return true;
	}
	bool updateSocketEpoll(int* p,int* pcount)
	{
		if(fdNumNow!=0)
			*pcount=fdNumNow;
		else
			return false;
		for(int i=0;i<fdNumNow;i++)
			p[i]=pfdn[i];
		return true;
	}
	bool sendSocketSelect(int toClient,const char* ps)
	{
		if(strlen(ps)>190)
			return false;
		memset(sen,0,200);
		strcpy(sen,ps);
		for(int i=0;i<fd_count;i++)
		{
			if(toClient==fdClients.fds_bits[i])
			{
				send(fdClients.fds_bits[i],sen,sizeof(sen),0);
				return true;
			}
		}
		return false;
	}
	bool sendSocketMystlSelect(int toClient,const void* ps,int len)
	{
		for(int i=0;i<fd_count;i++)
		{
			if(toClient==fdClients.fds_bits[i])
			{
				send(fdClients.fds_bits[i],(char*)ps,len,0);
				return true;
			}
		}
		return false;
	}
    bool sendEverySocket(void* ps,int len)
    {
        for(int i=0;i<fdNumNow;i++)
        {
            if(pfdn[i]!=0)
                send(pfdn[i],ps,len,0);
        }
        return true;
    }
	bool sendSocketAll(int socCli,const void* ps,int len)
	{
		if(send(socCli,(char*)ps,len,0)==-1)
			return false;
		return true;
	}
	int findSocketSelsct(int i)
	{
		if(fdClients.fds_bits[i]!=0)
			return fdClients.fds_bits[i];
		else
			return -1;
	}
	bool findSocketEpoll(int cliSoc)
	{
		for(int i=0;i<fdNumNow;i++)
		{
			if(pfdn[i]==cliSoc)
				return true;
		}
		return false;
	}
	char* getHostName()
	{
		char name[30]={0};
		gethostname(name,30);
		memcpy(hostname,name,30);
		return hostname;
	}
	bool epollModel(int* pthing,int* pnum,void* pget,int len,void* pneed,int (*pfunc)(int ,int ,void* ,void*,ServerTcpIp& ))
	{
		int eventNum=epoll_wait(epfd,pevent,512,-1);
		for(int i=0;i<eventNum;i++)
		{
			epoll_event temp=pevent[i];
			if(temp.data.fd==sock)
			{
				sockaddr_in newaddr={0};
				int newClient=accept(sock,(sockaddr*)&newaddr,(socklen_t*)&sizeAddr);
                this->addFd(newClient);
				nowEvent.data.fd=newClient;
				nowEvent.events=EPOLLIN;
				epoll_ctl(epfd,EPOLL_CTL_ADD,newClient,&nowEvent);
				*pthing=1;
				*pnum=newClient;
				strcpy((char*)pget,inet_ntoa(newaddr.sin_addr));
				if(pfunc!=NULL)
				{
					if(pfunc(*pthing,*pnum,pget,pneed,*this))
						return false;
				}
			}
			else
			{
				int getNum=recv(temp.data.fd,(char*)pget,len,0);
				*pnum=temp.data.fd;
				if(getNum>0)
					*pthing=2;
				else
				{
					*(char*)pget=0;
					*pthing=0;
                    this->deleteFd(temp.data.fd);
					epoll_ctl(epfd,temp.data.fd,EPOLL_CTL_DEL,NULL);
					close(temp.data.fd);
				}
				if(pfunc!=NULL)
				{
					if(pfunc(*pthing,*pnum,pget,pneed,*this))
						return false;
				}
			}
		}
		return true;
	}
};
int func(int thing,int num,void* p,void*,ServerTcpIp& it)
{
	if(thing==1)
		cout<<"some one in"<<endl;
	if(thing==0)
		cout<<"some out"<<endl;
	if(thing==2)
	{
		cout<<(char*)p<<endl;
		it.sendEverySocket(p,strlen((char*)p)+1);
	}
}
int main()
{
	ServerTcpIp server(512,5200,5);
	int thing=0,num=0;
	char get[100]={0};
	if(server.bondhost()==false)
		exit(0);
	if(server.setlisten()==false)
		exit(0);
	printf("server\n");
	while(1)
		server.epollModel(&thing,&num,get,100,NULL,func);
    return 0;
}
